import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Arrays;

/**
 * 91.解码方法
 * 一条包含字母 A-Z 的消息通过以下映射进行了 编码 ：
 * <p>
 * 'A' -> "1"
 * 'B' -> "2"
 * ...
 * 'Z' -> "26"
 * 要 解码 已编码的消息，所有数字必须基于上述映射的方法，反向映射回字母（可能有多种方法）。例如，"11106" 可以映射为：
 * <p>
 * "AAJF" ，将消息分组为 (1 1 10 6)
 * "KJF" ，将消息分组为 (11 10 6)
 * 注意，消息不能分组为 (1 11 06) ，因为 "06" 不能映射为 "F" ，这是由于 "6" 和 "06" 在映射中并不等价。
 * <p>
 * 给你一个只含数字的 非空 字符串 s ，请计算并返回 解码 方法的 总数 。
 * <p>
 * 题目数据保证答案肯定是一个 32 位 的整数。
 */
public class Decode {

    @Test
    public void test1() {
        Assertions.assertEquals(2, numDecoding("12"));
    }

    @Test
    public void test2() {
        Assertions.assertEquals(3, numDecoding("226"));
    }

    @Test
    public void test3() {
        Assertions.assertEquals(0, numDecoding("06"));
    }

    @Test
    public void test4() {
        Assertions.assertEquals(1, numDecoding("2101"));
    }

    @Test
    public void test5() {
        Assertions.assertEquals(1, numDecoding("10"));
    }

    @Test
    public void test6() {
        Assertions.assertEquals(0, numDecoding("0"));
    }

    @Test
    public void test7() {
        Assertions.assertEquals(5, numDecoding("1123"));
    }

    @Test
    public void test8() {
        Assertions.assertEquals(0, numDecoding("301"));
    }


    int numDecoding(String s) {

        if (s.length() == 1) {
            return isALetter(s, 0) ? 1 : 0;
        }

        int[] cache = new int[s.length()];

//        初始化 第0个字符
        if (isALetter(s, 0)) {
//          字符串的第0位解码之后是一个字母
            cache[0] = 1;
        } else {
            cache[0] = 0;
        }


        for (int i = 1; i < s.length(); i++) {

            if (isALetter(s, i)) {
//              第i位是一个字母
                cache[i] = cache[i - 1];
            }

            if (isALetter(s, i - 1, i)) {
//              第i-1位的数字和第i位的数组组合起来是一个字母
                if (i == 1) {
//                   防止数组越界
//                   两位数字的话，在cache[1] 的位置就最多只有2种情况
                    cache[i]++;
                } else {
//                  加上前两位的结果
                    cache[i] += cache[i - 2];
                }
            }
        }

        return cache[cache.length - 1];
    }

    boolean isALetter(String s, int index) {
        int i = strIndexToInt(s, index);
        return isALetter(i);
    }

    /**
     *
     * @param s
     * @param startIndex 包含
     * @param endIndex 包含
     * @return
     */
    private boolean isALetter(String s, int startIndex, int endIndex) {
        int ten = strIndexToInt(s, startIndex);
        int bit = strIndexToInt(s, endIndex);
        if (ten == 0) {
            return false;
        }
        return isALetter(ten * 10 + bit);
    }

    int strIndexToInt(String s, int index) {
        return Integer.parseInt(s.substring(index, index + 1));
    }


    boolean isALetter(int letterInt) {
        return letterInt > 0 && letterInt <= 26;
    }
}
